/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/

/* 
 promise是一个类,
*/

/*  resolve ，reject改变状态值，
    将频繁使用的变量值定义成常量
    方便复用，代码有提示
*/
const STATUS = {
    PENDING : 'pending', //等待
    FULFILLED : 'fulfilled', //成功
    REJECTED : 'rejected', //失败
}

class MyPromise {
    // 这个类被实例化，会立即执行，
    constructor (executor) {
        // 在构造函数里面有个执行器,如果在执行过程中出现错误，
        try{
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
    }
    // promise 状态值默认值等待,状态一旦更改就不能继续执行
    status = STATUS.PENDING;
    // value reason定义成实例属性，因为每个实例对象都有其对应的值
    // 成功之后的值
    value = undefined;
    // 失败之后的原因
    reason = undefined;
    // 成功回调,存储多个回调函数
    successCallback = [];
    // 失败回调
    failCallback = [];
    // this指向-指向实例对象 
    resolve = (value)=>{
        // 如果状态不是等待，阻止程序向下执行
        if(this.status !== STATUS.PENDING) return
        // 将状态更改为成功
        this.status = STATUS.FULFILLED;
        // 保存成功之后的值
        this.value = value;
        // 判断成功回调是否存在，如果存在 调用
        // this.successCallback && this.successCallback(this.value)
        while(this.successCallback.length) {
            // 删除数组第一个元素并返回被删除的第一个元素
            this.successCallback.shift()()
        }
    }
    reject = (reason) =>{
        // 如果状态不是等待，阻止程序向下执行
        if(this.status !== STATUS.PENDING) return
        // 将状态更改为失败
        this.status = STATUS.REJECTED;
        // 保存失败之后的原因
        this.reason = reason;
        // 判断成功回调是否存在，如果存在 调用
        // this.failCallback && this.failCallback(this.reason)
        while(this.failCallback.length) {
            // 删除数组第一个元素并返回被删除的第一个元素
            this.failCallback.shift()()
        }
    }

    // 多次调用then ，调用then的是promise then返回的应该是promise
    then (successCallback, failCallback) {
        // then方法中没有传递参数或者参数不是回调函数的情况。
        successCallback = successCallback ? successCallback : value => value;
        failCallback = failCallback ? failCallback : reason => { throw reason};
        // 对应调用下一个then的promise 因此
        let promise2 = new MyPromise((resolve, reject) => {
             // 判断状态，需要立即执行
            if (this.status === STATUS.FULFILLED) {
                // 这里调用promise2，是在promise2实例化的内部，所以同步获取不到该值，需要异步
                setTimeout(() => {
                    // then方法内执行出现错误
                    try{
                        let x = successCallback(this.value);
                        // 判断x的值是普通值还是promise对象
                        // 如果是普通值 直接调用promise
                        // 如果是promise对象，查看promise对象返回的结果
                        // 再根据promise对象返回的结果，决定调用resolve 还是调用reject
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e);
                    }
                }, 0)
            }else if (this.status === STATUS.REJECTED) {
                setTimeout(() => {
                    // then方法内执行出现错误
                    try{
                        let x = failCallback(this.reason);
                        // 判断x的值是普通值还是promise对象
                        // 如果是普通值 直接调用promise
                        // 如果是promise对象，查看promise对象返回的结果
                        // 再根据promise对象返回的结果，决定调用resolve 还是调用reject
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e);
                    }
                }, 0)
            } else {
                // 等待,异步情况的处理，将待执行的函数存储等待时机执行
                // 将成功回调和失败回调储存起来
                this.successCallback.push(()=>{
                    setTimeout(() => {
                        // then方法内执行出现错误
                        try{
                            let x = successCallback(this.value);
                            // 判断x的值是普通值还是promise对象
                            // 如果是普通值 直接调用promise
                            // 如果是promise对象，查看promise对象返回的结果
                            // 再根据promise对象返回的结果，决定调用resolve 还是调用reject
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                });
                this.failCallback.push(()=>{
                    setTimeout(() => {
                        // then方法内执行出现错误
                        try{
                            let x = failCallback(this.reason);
                            // 判断x的值是普通值还是promise对象
                            // 如果是普通值 直接调用promise
                            // 如果是promise对象，查看promise对象返回的结果
                            // 再根据promise对象返回的结果，决定调用resolve 还是调用reject
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                });
            }
        }); 
        return promise2;
    }
    catch (failCallback) {
        return this.then(undefined,failCallback)
    }
    //无论是成功还是失败都要调用这个回调函数，并且.then可以获得该promise的值
    // 支持异步
    finally (callback) {
        return this.then(value=>{ 
            return MyPromise.resolve(callback()).then(() => value)
        }, reason=>{
            return MyPromise.resolve(callback()).then(() => {throw reason})
        })
    }
   
    // 静态方法
    static all (array) {
        let result = [];
        let index = 0;
        return new MyPromise ((resolve, reject) => {
            function addData (key, value) {
                result[key] = value;
                index++;
                if (index === array.length) {
                    resolve(result);
                }
            }
            for(let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => addData(i, value), reason => reject(reason))
                }else {
                    // 普通值
                    addData(i, array[i]);
                }
            }
        })
    }
    // 将给定的值转换成promise对象
    static resolve (value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value))
    }

}

function resolvePromise(promise2, x, resolve, reject){
    // 错误：链式调用的promise是同一个promise 
    /*
        eg: var p1 = promise.then(value=>{return p1}) 
        调用then方法时，返回一个promise2也就是p1,然后再次返回的x也是p1。
     */
    if(promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<promise>'))
    }
    if (x instanceof MyPromise) {
        // promise对象
        // x.then((value) => resolve(value), (reason) => reject(reason))
        x.then(resolve, reject);
    } else {
        // 普通值
        resolve(x)
    }
}


/*
    1.Promise 即使一个类 在执行这个类的时候，需要传递一个执行器进去，执行器会立即执行
    2.Promise 中有三种状态 分别为 fulfilled 成功 rejected 失败  pending 等待
        pending --> fulfilled
        pending --> rejected
        一旦状态确定就不可更改
    3.resolve 和reject 函数是用来更改状态
        resolve ：fulfilled
        reject： rejected
    4. then 方法内部做得事情就是判断状态，如果成功，调用成功回调函数，如果状态失败，调用失败回调函数
     then方法是定义在原型对象中的
    5 then 成功回调有一个参数，表示成功之后的值 then失败回调有一个参数，表示失败的原因
    6. then 可以多次调用
    7.then 方法是可以被链式调用的，后面then方法的回调函数拿到的值的是上一个then方法的回调函数的返回值
    8.promise.all方法，按传入的顺序输出值，返回promise对象，都成功成功，有一个失败则失败
*/

let promise = new MyPromise((resolve, reject) => {
    // setTimeout(() => {
    //     resolve('成功');
    // }, 2000)
    // throw new Error('执行器错误')
    // resolve('成功');
    reject('失败')
})
function other() {
    return new MyPromise((resolve, reject) => {
        resolve('other')
    })
}

// promise.then((value) => {
//     console.log(value);
//     // return other();
//     return 'aaaa'
// }, (reason) => {
//     console.log(reason.message);
//     return 1000;
// })
promise.then().then()
// .then((value) => {
//     console.log(value);
//     return other();
// }, (reason) => {
//     console.log('aaaa');
//     console.log(reason.message);
// })
.then(value => {
    console.log(value);
}, reason=>console.log(reason));

 
